﻿#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
#include <opencv2/opencv.hpp>
#include <string>

#ifdef _WIN32  
#include <windows.h>  
#define DEFAULT_SAVING_PATH "C:/Users/Administration/Desktop/"
#define SLEEP_FOR_SECONDS(seconds) Sleep(seconds * 1000)  
#else  
#include <unistd.h>  
#define DEFAULT_SAVING_PATH "/tmp/"
#define SLEEP_FOR_SECONDS(seconds) usleep(seconds * 1000000)  
#endif  

class Camera 
{
public:
	Camera();
	~Camera();
public:
	//
	std::string rtpUrl;
	std::string savePath;

	cv::VideoCapture capture;
	int videoStopTag;

	/**
	 * @brief: 识别图像颜色
	 * @param img:	传入图片
	 * @param lower:	色域底
	 * @param upper:	色域顶
	 * @return: true --- 识别到颜色
	 *			false --- 未识别颜色
	*/
	bool colorRecog(cv::Mat img, cv::Scalar lower, cv::Scalar upper);

	/**
	 * @brief: 开始录像
	 * @param savepath:	录像存储路径
	 * @param stoparg:	停止标志位,进入videoBegin()后置1
	 * @return: 0 --- 成功
	 *			-1 --- 失败
	*/
	int videoBegin(cv::VideoCapture& capture, const std::string savepath, int& stoptag);

	/**
	 * @brief: 停止录像
	 * @param stoparg:	停止标志位,置0则退出videoBegin()循环
	*/
	void videoStop(int& stoptag);

	/**
	 * @brief: 500次开关机:测试是否进入桌面
	 * @param stoparg:	停止标志位,置0则退出videoBegin()循环
	*/
	bool isEnterDesktop(cv::VideoCapture& capture);


	/**
	 * @brief: 裁剪图片中间部分
	 * @param coefficient: 裁剪系数
	*/
	cv::Mat cropImageCenter(const cv::Mat& src, float coefficient);

	/**
	 * @brief: 根据系数绘制矩形
	 * @param coefficient: 系数(矩形编程/图片边长)
	*/
	cv::Mat drawRec(const cv::Mat& src, float coefficient);
};

Camera::Camera()
{
	this->rtpUrl = "rtsp://admin:hbw123456@192.168.1.64:554/Streaming/channels/101";
	this->savePath = DEFAULT_SAVING_PATH;
}

Camera::~Camera()
{
}

bool Camera::colorRecog(cv::Mat img, cv::Scalar lower, cv::Scalar upper)
{
	int count_all = 0, count_white = 0;
	cv::Mat hsv, mask;
	cvtColor(img, hsv, cv::COLOR_BGR2HSV);
	cv::inRange(hsv, lower, upper, mask);

	//cv::imshow("frame", img);
	//cv::imshow("hsv", hsv);
	cv::imshow("mask", mask);

	cv::Mat dst = cv::Mat(mask.size(), CV_8UC3);
	for (int i = 0; i < mask.rows; i++)
	{
		for (int j = 0; j < mask.cols; j++)
		{
			if (mask.channels() == 1)
			{
				count_all++;
				if (mask.at<uchar>(i, j) == 255)
					count_white++;
			}
		}
	}

	if ((float)count_white / count_all > 0.8f)
		return true;

	return false;
}

int Camera::videoBegin(cv::VideoCapture& capture, const std::string savepath, int& stoptag)
{
	if (!capture.isOpened())
	{
		std::cerr << "未打开摄像头" << std::endl;
		return -1;
	}

	int fps = (int)capture.get(cv::CAP_PROP_FPS);
	int width = (int)capture.get(cv::CAP_PROP_FRAME_WIDTH);
	int height = (int)capture.get(cv::CAP_PROP_FRAME_HEIGHT);

	if (fps <= 0 || width <= 0 || height <= 0)
	{
		fps = 30;
		width = 1920;
		height = 1080;
	}

	// 创建一个VideoWriter对象来保存视频  
	// 注意：根据OpenCV版本和编译设置，可能需要指定编码器的四个字符代码  
	// 例如，对于MP4文件，在Windows上可能是"XVID"或"mp4v"，在Linux上可能是"MP4V"  
	// 对于AVI文件，在Windows上可能是"DIVX"，在Linux上可能是"MJPG
	#ifdef __linux__  
	// Linux平台下的特定代码  
		cv::VideoWriter videoWriter(savepath + "output.avi", cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), fps, cv::Size(width, height));
	#elif defined(_WIN32)  
		cv::VideoWriter videoWriter(savepath + "output.avi", cv::VideoWriter::fourcc('D', 'I', 'V', 'X'), fps, cv::Size(width, height));
	#else	//其它
		cv::VideoWriter videoWriter(savepath + "output.avi", cv::VideoWriter::fourcc('D', 'I', 'V', 'X'), fps, cv::Size(width, height));
	#endif

	// 检查VideoWriter是否成功打开  
	if (!videoWriter.isOpened()) 
	{
		std::cerr << "无法打开视频写入器" << std::endl;
		capture.release();
		return -1;
	}

	cv::Mat frame;
	stoptag = 1;
	while (stoptag) 
	{
		capture >> frame; // 从摄像头捕获帧  
		if (frame.empty()) {
			std::cerr << "无法从摄像头读取帧" << std::endl;
			break;
		}

		videoWriter.write(frame); // 将帧写入视频文件  
		//cv::imshow("Camera", frame);
	}

	stoptag = 0;
	std::cout << "录像结束" << std::endl;
	return 0;
}

void Camera::videoStop(int& stoptag)
{
	stoptag = 0;
}

bool Camera::isEnterDesktop(cv::VideoCapture& capture)
{
	if (!capture.isOpened())
	{
		std::cout << "Failed to open camera" << std::endl;
		return false;
	}

	int fps = (int)capture.get(cv::CAP_PROP_FPS);
	int width = (int)capture.get(cv::CAP_PROP_FRAME_WIDTH);
	int height = (int)capture.get(cv::CAP_PROP_FRAME_HEIGHT);

	if (fps <= 0 || width <= 0 || height <= 0)
	{
		fps = 30;
		width = 1920;
		height = 1080;
	}

	cv::Mat frame(height, width, CV_8UC3);
	cv::Scalar lower_red(0, 43, 46);
	cv::Scalar upper_red(10, 255, 255);
#if 1 //Debug
	while (1)
#else	
	for(int i = 0;  i < 3; ++i, SLEEP_FOR_SECONDS(1))
#endif
	{
		capture.read(frame);
		cv::Mat temp = this->drawRec(frame, 0.5);
		cv::imshow("temp", temp);

		if (colorRecog(this->cropImageCenter(frame, 0.5), lower_red, upper_red))
		{
			frame.release();
			return true;
		}
		if (cv::waitKey(1) == 'q')
		{
			break;
		}
	}
	frame.release();
	return false;
}

cv::Mat Camera::cropImageCenter(const cv::Mat& src, float coefficient = 1.0) 
{
	if (src.empty()) 
	{
		std::cerr << "Input image is empty!" << std::endl;
		return cv::Mat();
	}

	int srcWidth = src.cols;
	int srcHeight = src.rows;

	int startX = (int)((srcWidth - (srcWidth * coefficient)) / 2);
	int startY = (int)((srcHeight - (srcHeight * coefficient)) / 2);

	cv::Rect cropRect(startX, startY, (int)(srcWidth * coefficient), (int)(srcHeight * coefficient));

	// 使用Rect对象截取图像
	cv::Mat croppedImage = src(cropRect);

	return croppedImage;
}

// 在原始图像上绘制截取区域的矩形(描边)
cv::Mat Camera::drawRec(const cv::Mat& src, float coefficient = 1.0)
{
	if (src.empty())
	{
		std::cerr << "Input image is empty!" << std::endl;
		return cv::Mat();
	}
	cv::Mat dst = src;

	int srcWidth = src.cols;
	int srcHeight = src.rows;

	int startX = (int)((srcWidth - (srcWidth * coefficient)) / 2);
	int startY = (int)((srcHeight - (srcHeight * coefficient)) / 2);

	cv::rectangle(dst, cv::Point(startX, startY), cv::Point(startX + (int)(srcWidth * coefficient), startY + (int)(srcHeight * coefficient)), cv::Scalar(0, 255, 0), 2);

	return dst;
}

int main(int argc, char* argv[])
{
	Camera camera;

	camera.capture = cv::VideoCapture(1);
	if (!camera.capture.isOpened())
	{
		std::cout << "Failed to open camera with index " << camera.rtpUrl << std::endl;
		return -1;
	}
	//开始录像
	//std::thread recordingThread(&Camera::videoBegin, &camera, std::ref(camera.capture), camera.savePath, std::ref(camera.videoStopTag));

	//判断
	if (camera.isEnterDesktop(camera.capture))
	{
		//true
		printf("Found\n");
	}
	else
	{
		//false
		printf("Not Found\n");
	}

	//录像结束
	//camera.videoStop(camera.videoStopTag);
	//recordingThread.join();
	return 0;
}